package BNS.graphs;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.StringTokenizer;

import javax.swing.JFrame;

import BNS.coloring.Simulation;
import BNS.plumbing.Library;


/** an extension to the Graph class that provides a way of specifying a Graph
	by reading an adjacency matrix from a file. 
	*/
public class MatrixGraph extends AnnotatedGraph {
	
	/**
   * 
   */
  private static final long serialVersionUID = 1L;
  public final String params, comment;
	public final int chromaticNumber, diameter, dominationRadius;
	public final double clusterQuotient;
	public final java.util.Date creationDate;
	/** Returns a String containing human-readable data pertaining to this graph. */
	public String getInfo() { 
		return params +" "+ comment +"\n"
		+" chromaticNumber="+ chromaticNumber
		+" diameter="+ diameter
		+" date= "+ creationDate;
		}
	
	/** Driver to create graphs, but does not store them. 
		Merely prints them on System.err, for testing this class. */
	public static void main(String[] args) throws IOException {
		System.err.println("MatrixGraph "+ args.length);
		Graph gr= null;
		if (args.length==0) gr= create();
		else gr= new MatrixGraph(new File(args[0]));
		if (gr!=null) {
			if(gr.numNodes()<20) gr.prettyPrint(System.err);
			else gr.histoDegrees(System.err);
			}
		else System.err.println("null graph");
		}
	
	/** Returns the results of create(). Probably obsolete.
		@param frame ignored.
		*/
	public static MatrixGraph create(JFrame frame) { return create(); }
	
	/** Obtains an adjacency matrix by prompting the user to select a file,
		and returns a Graph constructed from it.
		*/
	public static MatrixGraph create() {
		try {
			File file= Library.getSelectedFile();
			if (file!=null) return new MatrixGraph(file);	}
		catch(IOException e) { System.err.println(e); }
		return null;
		}
	/** Creates and returns a Graph from an adjacency matrix.
		Prints a message on System.err if an exception occurs.
		@param file the File where the matrix is stored. 
		*/
	public static MatrixGraph create(File file) {
		try { return new MatrixGraph(file);	}
		catch(IOException e) { System.err.println(e); }
		return null;
		}
	
	/** Creates a graph using a loop-free symmetric adjacency matrix as input.
		Each entry must be an int; non-zero entries will indicate an edge.
		The number of entries on the FIRST LINE of input will be taken as the # of nodes.
		Subsequent LINES must have the same number of entries on them.
		The "top right" of the matrix (above the diagonal) is definitive; other
		entries are not checked for compliance with the symmetry or no-loop conditions.
		@param file the text file containing the adjacency matrix 
		*/
	public MatrixGraph(File file) throws IOException {
		super(10,10);
		if(Simulation.DEBUG) System.err.println("generating MatrixGraph from "+ file);
		creationDate= new Date();
		this.params= file.toString();
		this.comment= "from adjacency matrix";
		FileReader frdr= new FileReader(file);
		BufferedReader rdr= new BufferedReader(frdr);
		
		int[] nmbrs= readLine(rdr);
		int size= nmbrs.length;
		Node[] nod= new Node[size];
		if(Simulation.DEBUG) System.err.println("MatrixGraph has size "+ size);
		//for(int t=0; t<size; t++) System.err.println(nmbrs[t]+": "+t);
//		Graph gr= new Graph(size,6*size);
		for(int t=0; t<size; t++) nod[t]= addNode("n"+(t+1));
		
		for(int t=0; t<size-1; t++) {	// matrix assumed to be symmetric
			for(int a=t; a<size; a++)	// use only the top right half of matrix
				if (nmbrs[a]!=0)
					addEdge(nod[t],nod[a]);
			nmbrs= readLine(rdr);
			}
		if(Simulation.DEBUG) System.err.println("MatrixGraph generated graph");
		chromaticNumber= 0;			// TODO: make this meaningful
		diameter= 0;				// TODO: make this meaningful
		dominationRadius= 0;		// TODO: make this meaningful
		clusterQuotient= 0.;		// TODO: make this meaningful		
		}
	
	/** Reads a line from a given BufferedReader, and converts it to an array
		of zeros and ones by testing to see if the first char of each token is a 0.
		*/
	private static int[] readLine(BufferedReader rdr) {
		String line= null;
		try { line= rdr.readLine(); }
		catch(Exception e) { System.err.println(e); }
		StringTokenizer st= new StringTokenizer(line);
		int i=0, size= st.countTokens();
		int[] nmbrs= new int[size];
		while (st.hasMoreTokens())
			nmbrs[i++]= st.nextToken().charAt(0)=='0'? 0:1;
		return nmbrs;
		}
	
	}
